Drawing Bézier Curves: The Swatch

I have a pseudo-artistic vision of drawing letters out of embedded letters at least two levels deep. Many letters that I want to draw use Bézier curves. I am learning about the math behind the curves and programming curve drawing from two articles on the internet. A third reference covers Bézier curves in SVG and is from Mozilla. My expectation is that I will be able to draw a given letter using Bézier curves and then scale, orient and place the letter as needed. I am also convinced that using SVG's textpath will not work. This doesn't allow the letters to be individually scaled to fit in place.

Javascript will be used to calculate the parameters for drawing each curve. The Javascript code will output SVG to render the image in the browser. This means that a Javascript series of functions will use some input to produce the desired curves. The curves will be assembled into letters. Each of the letters to be used needs to be broken down into a set of Bézier curves. The letters will be scaled, rotated and shifted to fit into or form a larger letter. Finally, the SVG code will be generated to display the letters. This will be done by outputting the SVG code to a div on the page.

My first task is to write Javascript code that will output some SVG code that will be rendered to the screen. Pretty trivial. The SVG code is just placed between backticks and returned to a div.innerHTML call. Next the letters need to be defined. My first font creation!?! Most of the Hebrew letters used are made of semi-rectangular blocks. The long sides of these blocks will be cubic Bézier curves and the shorter ends might be quadratic curves. There is one letter that is slightly more complex as shown below: from the left chet, waw, he, dalet, alef, and yod. The simplicity of the letters made from these shapes will make filling larger letters simpler. Upon rethinking this in light of writing the code, I am going to initially call each of these blocks the letters are composed of, swatches. Each swatch will be made with two quadratic bezier curves.

י א ד ה ו ח

The text to be successively embedded

Currently, I am using letters that are significantly different than those shown above. The Bézier curves needed for these letters are quadratic and cubic. The first has three control points: two locate the ends of the curve and one controls the tangency. Cubic curves have four control points: two locating the ends and two controlling tangency. Quadratic curves can be imitated by cubic curves if that simplifies programming. For the first letter from the left. The top will be made of two cubic Bézier curves connected at their ends. The vertical will be made similarly.

For the JavaScript code each letter will be an object that will be able to produce the SVG code to draw itself given its starting coordinates, size, and orientation. The prototype shape will be defined first. This prototype shape, which I will call a swatch, is the basic shape used multiple times in all of the letters used here. The swatch can be scaled, rotated and translated then combined with other swatches to make a letter. For example, The aleph will consist of three swatches. A large swatch that is rotated 45°, a medium swatch rotated 90° and translated left, and a small swatch translated up and to the right.

My first task is creating the six letter objects. The object, "letter", is defined. When a new "letter" is needed it is completed as follows. The number of swatches is set with setNumOfCurves(). The control points for each of the curves is set similarly with setControlPts(). I am no longer certain I have set up letter correctly. A letter consists of some number of swatches. Each swatch consists of some number of curves. Each curve consists of four control points. Ideally, each swatch will consist of two curves (or at least the same number of curves). Scale, orientation, and location will vary from swatch to swatch. The swatches are further constrained by the location, scale and orientation of the letter. The "letter" object above needs to reflect this predominance of swatches over curves.

The current program assumes that all swatches are defined by two bezier curves. There is a generic swatch, swatch, that is used for all subsequent swatches through scaling, translating, and rotating. letter2 is the latest iteration of this concept. It contains an array of swatches called swatches. This array holds the location, size and rotation for each of the swatches. The number of swatches is stored in numOfSwatches.

The letter2 object has multiple methods. It has getters and setters for the name, numOfSwatches, swatches. There is also a method to add swatches one-by-one to swatches. Finally, there is a method to draw itself, createSVG. This method simply iterates over the swatches array for numOfSwatches times. It takes the translation, scale and rotation data from the individual swatch and applies this to the generic swatch. It sends the array so produced to makeSVG to produce the requisite text string, newSVG.

Below is the SVG for the generic swatch and a rendered generic swatch. A yod is just this generic swatch rotated 30°. One letter completed.

<"svg" viewbox= "0 0 300 300" width="300" height="300">
<"path" d= "M 32 146 C 86 201, 175 15, 227 146" stroke="black" fill="transparent" />
<"path" d= "M 32 146 C 86 277, 175 91, 227 146" stroke="black" fill="transparent" />
<"/svg">

After playing with functioning yod output I realized that rotating around one of the control points is not a great solution. Rotation should be around the center of mass of the swatch. Since rotation is done prior to translation this should be doable in a generic sense. That is the generic swatch is first rotated, then it is scaled, and finally it is translated to its final resting spot. The center of mass of the swatch should be centered between the first and last control points and on the same line. The first control point is [0.032,0.146] and the last is [0.227,0.146]. The center point is [0.1295,0.146]. The generic swatch needs to be translated by this amount prior to rotation and then translated back. Works as planned!

The next steps will require modifying the code already written. I don't want to completely lose what I have accomplished, so this page will remain intact to document version one.

This raises the real conundrum with which I am now wrestling. How does one propagate the various rotations and translations down through the various levels to finally arrive at swatches that render themselves in the appropriate location and orientation?



Create a Bézier Curve Swatch: